package org.dea.facade;

import java.io.File;
import java.lang.reflect.Modifier;
import java.util.Iterator;
import java.util.Vector;

import org.dea.util.SourceUtil;

import de.gulden.util.javasource.Class;
import de.gulden.util.javasource.Constructor;
import de.gulden.util.javasource.Parameter;

public class RMIFacadeMaker implements FacadeMaker{
	
	public static final String RMI_PREFIX = "RMI";
	public static final String IF_PREFIX = RMIInterfaceFacadeMaker.IF_PREFIX;

	public Class generateFacade(File sourceDir, String fullQualifiedName) throws Exception{
		Class baseClass = SourceUtil.loadClassSource(sourceDir, fullQualifiedName);
		if( baseClass == null )
			throw new RuntimeException("Class "+fullQualifiedName+" does not exist on sourceDir "+ sourceDir);
		
		String ifType = IF_PREFIX+baseClass.getUnqualifiedName();
		String type = RMI_PREFIX+baseClass.getUnqualifiedName();


		SourceUtil.addInterfaces(baseClass, ifType);
		SourceUtil.changeClassName(baseClass, type);
		SourceUtil.changeSuperClass(baseClass, "UnicastRemoteObject");
		addMain(baseClass, ifType, type);
		addShutdown(baseClass, ifType, type);
		addPing(baseClass, ifType, type);
		SourceUtil.addExceptionAllMethods(baseClass, "RemoteException" );
		SourceUtil.addImport(baseClass, "java.rmi", "*");
		SourceUtil.addImport(baseClass, "java.rmi.server", "*");
		SourceUtil.addImport(baseClass, "java.rmi.registry", "*");
		SourceUtil.generateSourceFile(sourceDir, baseClass);
		return baseClass;
	}
	
	private void addMain( Class baseFacadeClass, String facadeType, String type ){
		
		String[] voidArgs = {}, stringArgs = { "String[]" };
		boolean containsVoid = SourceUtil.getConstructor(baseFacadeClass, voidArgs ) != null;
		boolean containsStringArgs = SourceUtil.getConstructor(baseFacadeClass, stringArgs ) != null;

		if( !containsVoid && !containsStringArgs ){
			throw new RuntimeException("Original facade must contain voi or String[] constructor");
		}
		
		String codeRaw = "";
		if( containsVoid ){
			codeRaw += "if( args.length == 1 ){";
			codeRaw += "\tRegistry registry = LocateRegistry.createRegistry(Integer.parseInt(args[0]));\n";
			codeRaw += "\ttry{\n";
			codeRaw += "\t\t"+facadeType+" facade = new "+type+"();\n";
			codeRaw += "\t\tregistry.bind(\""+facadeType+"\", facade);\n";
			codeRaw += "\t} catch (Exception ex){ ex.printStackTrace(); }\n";
			codeRaw += "} else ";
		}
		
		if( containsStringArgs ){
			codeRaw +=	"if(args.length >1){\n";
			codeRaw += "\tString[] newArgs = new String[args.length-1];\n";
			codeRaw += "\tfor(int i=1; i<args.length;i++){ newArgs[i-1] = args[i];}\n";
			codeRaw += "\tRegistry registry = LocateRegistry.createRegistry(Integer.parseInt(args[0]));\n";
			codeRaw += "\ttry{\n";
			codeRaw += "\t\t"+facadeType+" facade = new "+type+"(newArgs);\n";
			codeRaw += "\t\tregistry.bind(\""+facadeType+"\", facade);\n";
			codeRaw += "\t} catch (Exception ex){ ex.printStackTrace(); }\n";
			codeRaw += "} else ";
		}
		
		codeRaw += "{ throw new RuntimeException(\"Invalid number of parameters\"+ args.length ); }\n ";
		String[] paramNames ={ "args" };
		String[] paramTypes ={ "String[]" };
		SourceUtil.addMethod(baseFacadeClass, Modifier.PUBLIC + Modifier.STATIC, "main", paramNames , paramTypes, "void", codeRaw );
	}
	
	private void addShutdown( Class baseFacadeClass, String facadeType, String type ){
		String codeRaw = "";
		codeRaw += "org.dea.util.ExitTimer.exit(1000);\n";
//		codeRaw += "new Thread(){\n";
//		codeRaw += "public void run(){\n";
//		codeRaw += "try{\n";
//		codeRaw += "\tThread.sleep( 1000 );\n";
//		codeRaw += "} catch (Exception ex){ ex.printStackTrace(); }\n";
//		codeRaw += "System.exit( 0 );\n";
//		codeRaw += "}\n}.start();\n";
		String[] paramNames ={};
		String[] paramTypes ={};
		SourceUtil.addMethod(baseFacadeClass, Modifier.PUBLIC , "distributedEasyAcceptShutdown", paramNames , paramTypes, "void", codeRaw );
	}
	
	private void addPing( Class baseFacadeClass, String facadeType, String type ){
		String codeRaw = "";
		codeRaw += "return true;\n";
		String[] paramNames ={};
		String[] paramTypes ={};
		SourceUtil.addMethod(baseFacadeClass, Modifier.PUBLIC , "distributedEasyAcceptPing", paramNames , paramTypes, "boolean", codeRaw );
	}
	
	public static void main(String[] args) throws Exception {
		new RMIFacadeMaker().generateFacade(new File("test"), "somepack.innerpack.Simple");
	}
	



}
